/*
 * anima/x86_64/atomic.hh - x86-64 atomic variables implementation.
 * Copyright (C) 2007  Mikhail Vorozhtsov
 * See the LICENSE section of the README file for details.
 */

/* $Id$ */

#ifndef HEADER_ANIMA_X86_64_ATOMIC_HH
#define HEADER_ANIMA_X86_64_ATOMIC_HH

START_NAMESPACE2 (anima,x86_64)

template <typename T>
struct atomic_t;

#define __ANIMA_X86_64_ATOMIC(BITS,SUFFIX) \
  template <> \
  struct atomic_t<u ## BITS ## _t> \
  { \
  private: \
    volatile u ## BITS ## _t value; \
    \
  public: \
    INLINE \
    atomic_t () \
    { \
    } \
    \
    INLINE \
    atomic_t (u ## BITS ## _t value) \
    { \
      this->value = value; \
    } \
    \
  public: \
    INLINE \
    u ## BITS ## _t \
    get () \
    { \
      return value; \
    } \
    \
    INLINE \
    u ## BITS ## _t \
    set (u ## BITS ## _t x) \
    { \
      asm volatile ( \
        "xchg" SUFFIX " %0, %1\n" \
        : "+a" (x), "+m" (value) \
      ); \
      \
      return x; \
    } \
    \
    INLINE \
    bool \
    set_if_eq (u ## BITS ## _t x, u ## BITS ## _t test) \
    { \
      u ## BITS ## _t result = 0; \
      \
      asm volatile ( \
        "lock cmpxchg" SUFFIX " %0, %1\n" \
        "jnz 1f\n" \
        "mov" SUFFIX " $1, %2\n" \
        "1:\n" \
        : "+r"(x), "+m"(value), "=r"(result) \
        : "a"(test) \
      ); \
      \
      return result; \
    } \
    \
    INLINE \
    bool \
    set_bit (u8_t index, bool present_p = true) \
    { \
      bool result = false; \
      \
      if (present_p) \
        asm volatile ( \
          "lock bts" SUFFIX " %2, %0\n" \
          "jnc 1f\n" \
          "mov $1, %1\n" \
          "1:\n" \
          : "+m"(value), "=r"(result) \
          : "r"((u ## BITS ##_t) index) \
        ); \
      else \
        asm volatile ( \
          "lock btr" SUFFIX " %2, %0\n" \
          "jnc 1f\n" \
          "mov $1, %1\n" \
          "1:\n" \
          : "+m"(value), "=r"(result) \
          : "r"((u ## BITS ## _t) index) \
        ); \
      \
      return result; \
    } \
    \
    INLINE \
    u ## BITS ## _t \
    add (u ## BITS ## _t x = 1) \
    { \
      u ## BITS ## _t tmp = x; \
      \
      asm volatile ( \
        "lock xadd" SUFFIX " %0, %1\n" \
        : "+r" (x), "+m" (value) \
      ); \
      \
      return x + tmp; \
    } \
    \
    INLINE \
    u ## BITS ## _t \
    sub (u ## BITS ## _t x = 1) \
    { \
      return add (-x); \
    } \
  } PACKED;

__ANIMA_X86_64_ATOMIC (8, "b")
__ANIMA_X86_64_ATOMIC (16, "w")
__ANIMA_X86_64_ATOMIC (32, "l")
__ANIMA_X86_64_ATOMIC (64, "q")

#undef __ANIMA_X86_64_ATOMIC

END_NAMESPACE2

#endif /* HEADER_ANIMA_X86_64_ATOMIC_HH */

